from common import *


class PreparedBefore():
    def __init__(self):
        SolutionGetFirstFollow()

        # self.print_First_Follow_set()

        GetPredictiveTable()

    def print_First_Follow_set(self):
        print("FIRST:")
        for first in First:
            print(first)

        print("FOLLOW:")
        for follow in Follow:
            print(follow)



class SolutionGetFirstFollow():
    def __init__(self):
        self.class_get_first_set()
        self.class_get_follow_set()

    def class_get_first_set(self):  # 获取First集合
        for vn in Vn:
            First[vn] = []
            # 对于每一个文法，开始时，都是空

        continue_flag = True
        # 当没有改变时停止
        while continue_flag:
            continue_flag = False

            for Deduction_Left, Reflections_Right in Grammar.items():

                #   Deduction_Left 为grammar.txt的左侧部分
                #   Reflection_Right    为Deduction_Left推到出的右边元素的集合
                Left_First_Len_Before = len(First.get(Deduction_Left))  # 查看left在first集合中的长度，用于判断是否结束循环
                # 得到 每一个映射
                # S->['a A', 'b']
                for Each_Reflection in Reflections_Right:
                    # S->'a A'
                    Each_Reflection = Each_Reflection.split(' ')
                    # S->['a','A']
                    # 对每个单独规则的单独项，如aA的a和A
                    for i, Per_Reflection in enumerate(Each_Reflection):

                        if Per_Reflection in Vn:  # 非终结符 left->g(S->A)
                            tmp_left_first = First.get(Deduction_Left) \
                                if First.get(Deduction_Left) is not None else []
                            #   获取First集合里面的

                            tmp_Right_de_first = First.get(Per_Reflection).copy() \
                                if First.get(Per_Reflection) is not None else []
                            #   获取右边一个元素的first集合

                            if '$' in tmp_Right_de_first:  # 是一连串非终结符 则中间的去掉空 结尾的保留空
                                if i != len(Each_Reflection) - 1:  # 按照算法，如果Yj的推导中存在空，则删除空，同时加入到First集合中
                                    tmp_Right_de_first.remove('$')

                            Res_joint_First = tmp_left_first + tmp_Right_de_first  # 将两个First集合结合
                            Res_joint_First = list(set(Res_joint_First))  # 格式化
                            First[Deduction_Left] = Res_joint_First
                            if '$' not in First.get(Per_Reflection):
                                break

                        else:  # 终结符或$ 直接加入并结束，顺序同上
                            tmp_left_first = First.get(Deduction_Left) if First.get(Deduction_Left) is not None else []
                            tmp_Right_de_first = [Per_Reflection]
                            Res_joint_First = tmp_left_first + tmp_Right_de_first
                            Res_joint_First = list(set(Res_joint_First))
                            First[Deduction_Left] = Res_joint_First
                            break

                # 操作前后长度对比，因为只可能往里加
                Left_First_Len_After = len(First.get(Deduction_Left))
                if Left_First_Len_Before < Left_First_Len_After:
                    continue_flag = True

    def class_get_follow_set(self):
        for vn in Vn:  # grammar 箭头左边部分，即产生式左侧
            Follow[vn] = []  # 初始化

        Follow[Start_flag] = ['#']  # 向开始符号的FOLLOW集合里加入#

        continue_flag = True  # 结束记号

        while continue_flag:
            continue_flag = False
            # 对于每个终结符vn 比如要找G的
            for vn in Vn:
                Follow_set_len_before = len(Follow.get(vn))  # 获取此时，vn的FOLLOW集合长度，如果结束时没变，则说明算法结束了
                # 在每个Grammar里找 形如 {'functionCall'=['AVG G', 'MAX']}
                for Deduction_Left, Reflections_Right in Grammar.items():
                    # 对于每一个grammar.txt文件中左右两个部分，Deduction_Left为左边，Reflections_Right为右边
                    # 对functionCall -> 'AVG G'
                    for Each_Reflection in Reflections_Right:  # 相当于研究： k->v
                        Each_Reflection = Each_Reflection.split(' ')
                        ff = 0  # 判断符号，判断是否读到了A->αBβ情况
                        for i, Per_Reflection in enumerate(Each_Reflection):
                            # AVG不是该vn
                            if Per_Reflection != vn:  # s为终结符，对应读到了 A->αBβ情况
                                if ff == 0:  # 对应A->αBβ读到了B，需要往后读β的情况
                                    continue
                                # 当ff==1 也就是前一个是所求vn
                                else:  # 读到了β
                                    # cnmd β是到最后的长串
                                    # 先将后面的First去ε加入follow

                                    # -----------------------------------------------------------------------------------
                                    # 获得first(β）
                                    First_B_str = ''
                                    for j in range(i, len(Each_Reflection)):
                                        First_B_str += Each_Reflection[j]
                                        if j != len(Each_Reflection) - 1:
                                            First_B_str += ' '
                                    # First_B_str为字符串

                                    self.get_B_First(First_B_str, First, Vn)  # 找到目标的First集合

                                    Aim_First_B = First_str.get(First_B_str).copy()
                                    # 将目标First集合的内容复制到tmp1中

                                    # ------------------------------------------------------------------------------------
                                    # 不是None 最多是[]
                                    # 将First\{} 加入到Follow中
                                    Follow_aim = Follow.get(vn)
                                    if '$' in Aim_First_B:
                                        Aim_First_B.remove('$')
                                        # 将follow(左)加入follow(vn)

                                        Follow_aim_tmp = Follow.get(Deduction_Left)
                                        Follow_aim += Follow_aim_tmp

                                    Follow_aim = list(set(Follow_aim + Aim_First_B))
                                    Follow[vn] = Follow_aim  # 将First(β)\{空} 加入到FOLLOW(B)中
                                    # ------------------------------------------------------------------------------------

                                    ff = 0

                            # 遇到该vn
                            elif Per_Reflection == vn:  # 对应 A-> αB的情况
                                # 最后遇到 将Follow(k)中的全部内容加到Follow(vn)
                                if i == len(Each_Reflection) - 1:  # 对应此时i读到了B的情况
                                    Follow_left = Follow.get(Deduction_Left).copy() if Follow.get(
                                        Deduction_Left) is not None else []  # FOLLOW（A）
                                    Follow_right = Follow.get(vn).copy() if Follow.get(
                                        vn) is not None else []  # FOLLOW（B）
                                    Res_Follow = list(set(Follow_left + Follow_right))
                                    Follow[vn] = Res_Follow
                                # 不是最后一个 要处理下一个
                                else:  # 对应此时没读到最后
                                    ff = 1

                Follow_set_len_after = len(Follow.get(vn))  # 项目个数
                if Follow_set_len_before < Follow_set_len_after:
                    continue_flag = True

    def get_B_First(self, in_str, First, Vn):
        l_str = in_str.split(' ')  # ['Cc']
        for i, each in enumerate(l_str):
            # 在这里处理一下终结符的First集
            if each not in Vn:
                First[each] = [each]
                # 此处将First集合初始化

            tmp1 = First_str.get(in_str).copy() if First_str.get(in_str) is not None else []
            tmp2 = First.get(each).copy()
            # tmp1，2为记录

            if '$' in tmp2:
                if i != len(l_str) - 1:
                    tmp2.remove('$')
            # 根据算法，如果有空符，需要去掉

            tmp = tmp1 + tmp2
            if len(tmp) > 1:  # 如果First集合大于1
                tmp = list(set(tmp))
            First_str[in_str] = tmp

            if '$' not in First.get(each):
                break
        return First_str.get(in_str)


class GetPredictiveTable():
    for i in range(100):
        pass

    def __init__(self):
        self.Get_Table()

    def get_FirstSet_str(self, in_str, First, Vn):
        l_str = in_str.split(' ')  # ['Cc']
        for i, each in enumerate(l_str):
            # 在这里处理一下终结符的First集
            if each not in Vn:
                First[each] = [each]
                # 此处将First集合初始化

            tmp1 = First_str.get(in_str).copy() if First_str.get(in_str) is not None else []
            tmp2 = First.get(each).copy()
            # tmp1，2为记录

            if '$' in tmp2:
                if i != len(l_str) - 1:
                    tmp2.remove('$')
            # 根据算法，如果有空符，需要去掉

            tmp = tmp1 + tmp2
            if len(tmp) > 1:  # 如果First集合大于1
                tmp = list(set(tmp))
            First_str[in_str] = tmp

            if '$' not in First.get(each):
                break
        return First_str.get(in_str)

    def Get_Table(self):
        for Deduction_Left, Reflections_Right in Grammar_v2.items():  # 对于Gramma表里的左右项目进行操作

            FirstSetRight = self.get_FirstSet_str(Reflections_Right, First, Vn)  # 获取右侧映射的First集合

            for Element in FirstSetRight:

                if Element not in Vn and Element != '$':  # 遇到终结符
                    M[(Deduction_Left[0], Element)] = [Deduction_Left[0], Reflections_Right, Deduction_Left[1]]

                if Element == '$':  # 遇到ε 求左端Follow
                    LeftFollowSet = Follow[Deduction_Left[0]]
                    for ElementLeft in LeftFollowSet:

                        if ElementLeft not in Vn and ElementLeft != '$':  # 对Follow中的每个终结符
                            M[(Deduction_Left[0], ElementLeft)] = [Deduction_Left[0], Reflections_Right,
                                                                   Deduction_Left[1]]
                            # ε同时在follow和first中
                            if ElementLeft == '#':
                                M[(Deduction_Left[0], '#')] = [Deduction_Left[0], Reflections_Right, Deduction_Left[1]]
